package wechatpay

import (
	"crypto"
	"crypto/aes"
	"crypto/cipher"
	"crypto/rsa"
	"crypto/sha1"
	"crypto/sha256"
	"crypto/x509"
	"encoding/base64"
	"encoding/hex"
	"encoding/pem"
	"errors"
	"io/ioutil"
	"yundian/internel/app/models/paysetting"
)

// ------------ Api v3 - payCrypto(支付加解密相关) -----------------//

// SHA-256-RSA 商户私钥加密
func SHA256WithRsaBase64(origData string, wc *paysetting.PaySetting) (sign string, err error) {
	//wxConfig := GetWxPaySetting()
	//block, _ := ioutil.ReadFile(wxConfig.ApiclientKeyPath) // 商户私钥
	//block, _ := ioutil.ReadFile("./configs/certs/apiclient_key.pem") // 商户私钥
	block, _ := ioutil.ReadFile(wc.ApiclientKeyPath) // 商户私钥
	privateKey, err := ParsePrivateKey(block)                        // 解析私钥
	if err != nil {
		return "", err
	}

	h := sha256.New()
	h.Write([]byte(origData))
	digest := h.Sum(nil) // 附加

	s, _ := rsa.SignPKCS1v15(nil, privateKey, crypto.SHA256, digest) // 加密
	sign = base64.StdEncoding.EncodeToString(s)                      // base64编码
	return
}

// AES-256-GCM 解密
func AesGcmDecrypt(cipherText, nonceStr, associatedStr, apiKeyV3 string) (string, error) {
	key := []byte(apiKeyV3)                 // APIv3密钥，长度32位，由管理员在商户平台上自行设置的
	additionalData := []byte(associatedStr) // 附加数据包
	nonce := []byte(nonceStr)               // 加密使用的随机串初始化向量

	block, err := aes.NewCipher(key)
	if err != nil {
		return "", err
	}

	aesGcm, err := cipher.NewGCMWithNonceSize(block, len(nonce))
	if err != nil {
		return "", err
	}

	cipherData, _ := base64.StdEncoding.DecodeString(cipherText)
	plainData, err := aesGcm.Open(nil, nonce, cipherData, additionalData)
	if err != nil {
		return "", err
	}

	return string(plainData), err
}

// SHA1 加密码
func SHA1(rawData string, sessionKey string) string {
	key := StrJoin(rawData, sessionKey)
	h := sha1.New()
	h.Write([]byte(key))
	return hex.EncodeToString(h.Sum(nil))
}

// 解析 Certificate
func ParseCertificate(pemData []byte) (*x509.Certificate, error) {
	block, _ := pem.Decode(pemData)
	if block == nil {
		return nil, errors.New("解码包含平台公钥的PEM块失败")
	}

	certi, err := x509.ParseCertificate(block.Bytes)
	if err != nil {
		return nil, err
	}

	return certi, nil
}

// 解析 private Key
func ParsePrivateKey(pemData []byte) (*rsa.PrivateKey, error) {
	block, _ := pem.Decode(pemData)
	if block == nil || block.Type != "PRIVATE KEY" {
		return nil, errors.New("未能解码PUBLIC KEY")
	}

	priInterface, err := x509.ParsePKCS8PrivateKey(block.Bytes)
	if err != nil {
		return nil, err
	}

	//fmt.Printf("Got a %T, with remaining data: %q", priInterface, rest)
	return priInterface.(*rsa.PrivateKey), nil
}

// 解析 public key
func ParsePublicKey(pemData []byte) (*rsa.PublicKey, error) {
	block, _ := pem.Decode(pemData)
	if block == nil {
		return nil, errors.New("获取公钥失败")
	}

	pubInterface, err := x509.ParsePKIXPublicKey(block.Bytes)
	if err != nil {
		return nil, err
	}

	//fmt.Printf("Got a %T, with remaining data: %q", pubInterface, rest)
	return pubInterface.(*rsa.PublicKey), nil
}

/*func RsaEncrypt(origData []byte) (string, error) {
	publicKey := []byte(`平台证书公钥`)
	block, _ := pem.Decode(publicKey)
	if block == nil {
		return "", errors.New("public key error")
	}
	pubInterface, err := x509.ParsePKIXPublicKey(block.Bytes)
	secretMessage := origData
	rng := rand.Reader

	cipherdata, err := rsa.EncryptOAEP(sha1.New(), rng, pubInterface.(*rsa.PublicKey), secretMessage, nil)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error from encryption: %s\n", err)
	}

	ciphertext := base64.StdEncoding.EncodeToString(cipherdata)
	fmt.Printf("Ciphertext: %x\n", ciphertext)
	return ciphertext, err

}*/

// AES-ECB 解密
/*func AesDecrypt(ciphertext string) string {
	key := []byte(ConfigV3.ApiKey()) // 加密的密钥
	encrypted, err := base64.StdEncoding.DecodeString(ciphertext)
	if err != nil {
		fmt.Println(err)
		return ""
	}

	genKey := make([]byte, 16)
	copy(genKey, key)
	for i := 16; i < len(key); {
		for j := 0; j < 16 && i < len(key); j, i = j+1, i+1 {
			genKey[j] ^= key[i]
		}
	}

	cipher, _ := aes.NewCipher(genKey)
	decrypted := make([]byte, len(encrypted))

	for bs, be := 0, cipher.BlockSize(); bs < len(encrypted); bs, be = bs+cipher.BlockSize(), be+cipher.BlockSize() {
		cipher.Decrypt(decrypted[bs:be], encrypted[bs:be])
	}

	trim := 0
	if len(decrypted) > 0 {
		trim = len(decrypted) - int(decrypted[len(decrypted)-1])
	}

	decrypted = decrypted[:trim]

	log.Println("解密结果：", string(decrypted))
	return string(decrypted)
}*/

// CBC 模式
//解密
/**
* rawData 原始加密数据
* key  密钥
* iv  向量
 */
func Dncrypt(rawData, key, iv string) (string, error) {
	data, err := base64.StdEncoding.DecodeString(rawData)
	key_b, err_1 := base64.StdEncoding.DecodeString(key)
	iv_b, _ := base64.StdEncoding.DecodeString(iv)
	if err != nil {
		return "", err
	}
	if err_1 != nil {
		return "", err_1
	}
	dnData, err := AesCBCDncrypt(data, key_b, iv_b)
	if err != nil {
		return "", err
	}
	return string(dnData), nil
}

// 解密
func AesCBCDncrypt(encryptData, key, iv []byte) ([]byte, error) {
	block, err := aes.NewCipher(key)
	if err != nil {
		panic(err)
	}
	blockSize := block.BlockSize()
	if len(encryptData) < blockSize {
		panic("ciphertext too short")
	}
	if len(encryptData)%blockSize != 0 {
		panic("ciphertext is not a multiple of the block size")
	}
	mode := cipher.NewCBCDecrypter(block, iv)
	mode.CryptBlocks(encryptData, encryptData)
	// 解填充
	encryptData = PKCS7UnPadding(encryptData)
	return encryptData, nil
}

//去除填充
func PKCS7UnPadding(origData []byte) []byte {
	length := len(origData)
	unpadding := int(origData[length-1])
	return origData[:(length - unpadding)]
}
